05. NumPy 中的元素级运算

元素级运算

Python 中的方式

假设你有一个数字列表,你想向列表中的每一项加上 5 。如果没有 NumPy,你可以像下面这样做:

values = [1,2,3,4,5]
for i in range(len(values)):
    values[i] += 5

# 现在的 values 为 [6,7,8,9,10]

这是讲得通的,但是你要编写很多代码,而且因为它是纯 Python,所以运行的很慢。

注意: 如果你不习惯使用像 += 这样的运算符,它的意思是"将两者相加,然后将结果保存在左边的项中"。这是 values[i] = values[i] + 5 的简便写法。你在这些示例中看到的代码会尽可能地使用此类运算符。

NumPy 中的方式

在 NumPy 中,我们可以这么做:

values = [1,2,3,4,5]
values = np.array(values) + 5

# 现在 values 是包含 [6,7,8,9,10] 的一个 ndarray

创建该数组可能看起来很奇怪,但通常你总是要将数据存储在 ndarray 中的。所以如果你已经有一个名为 valuesndarray,你可以这么做:

values += 5

我们应该指出,NumPy 实际上有用于加法、乘法等运算的函数。但它也支持使用标准的数学运算符。所以以下两行是等价的:

x = np.multiply(some_array, 5)
x = some_array * 5

我们通常会使用运算符而不是函数,因为它们更方便键入,也更容易阅读,不过这只是个人偏好。

再看一个使用标量和 ndarrays 进行运算的例子。假设你有一个矩阵 m 并且你想复用它,但首先你需要将其所有值设为零。这很简单,只需给它乘以零,并将结果赋值回原矩阵就行了,如下所示:

m *= 0

# 现在 m 中的每个元素都是 0,无论它有多少维度

元素级矩阵运算

与标量和矩阵一起使用的相同函数和运算符也适用于其他维度。你只需要确保执行运算的项目具有兼容的形状。

假设你想得到矩阵的平方值。方法是 x = m * m(或者如果你要将值赋值回 m,则是 m *= m

这是可行的,因为它是两个形状相同的矩阵之间的元素乘法。(在这个例子中,它们的形状相同,是因为它们实际上是同一个对象。)

看看视频中的一个示例:

a = np.array([[1,3],[5,7]])
a
# 显示以下结果:
# array([[1, 3],
#        [5, 7]])

b = np.array([[2,4],[6,8]])
b
# 显示以下结果:
# array([[2, 4],
#        [6, 8]])

a + b
# 显示以下结果:
#      array([[ 3,  7],
#             [11, 15]])

如果你尝试使用不兼容的形状,就像视频中的另一个示例一样,你会收到一个错误:

a = np.array([[1,3],[5,7]])
a
# 显示以下结果:
# array([[1, 3],
#        [5, 7]])
c = np.array([[2,3,6],[4,5,9],[1,8,7]])
c
# 显示以下结果:
# array([[2, 3, 6],
#        [4, 5, 9],
#        [1, 8, 7]])

a.shape
# 显示以下结果:
#  (2, 2)

c.shape
# 显示以下结果:
#  (3, 3)

a + c
# 显示以下结果:
# ValueError: operands could not be broadcast together with shapes (2,2) (3,3) 

你会在后面的课程中详细了解“不能一起广播”的意义,现在只需注意这两种形状是不同的,因此我们无法执行元素级运算。